home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™94 / Miscellaneous / Randy Thelen / ThreadedSort / Misc Stuff / TextView.cp < prev    next >
Encoding:
Text File  |  1994-06-26  |  21.8 KB  |  771 lines  |  [TEXT/MPS ]

  1. #include    <Types.h>
  2. #include    <Memory.h>
  3. #include    <QuickDraw.h>
  4. #include    <Fonts.h>
  5. #include    <Packages.h>
  6. #include    <TextUtils.h>
  7.  
  8. #include     <LowMem.h>        //    LMSetHiliteMode()
  9.  
  10. #include    "TextView.h"
  11.  
  12.  
  13. #ifndef    qSelectionByCharacter
  14. #define    qSelectionByCharacter    1
  15. #endif
  16.  
  17. //    Private Function Prototypes
  18.  
  19. static void    SetHiliteMode(void)
  20.     {
  21.     LMSetHiliteMode(LMGetHiliteMode() & ~(1 << 7));
  22.     }
  23.     
  24. static    pascal void    TextViewActionProc(ControlHandle theControl,short partCode);
  25.  
  26. ControlActionUPP    gTextViewActionUPP = NewControlActionProc(TextViewActionProc);
  27.  
  28.  
  29. TTextViewHandle    NewTextView(WindowPtr theWindow,Rect *viewRect)
  30.     {
  31.     TTextViewHandle    theTextView;
  32.     Rect            vScrollbarRect,hScrollbarRect;
  33.     
  34.     theTextView = (TTextViewHandle) NewHandle(sizeof(TTextView));
  35.     if (theTextView != nil)
  36.         {
  37.         (*theTextView)->fWindow = theWindow;
  38.         (*theTextView)->fViewRect = *viewRect;
  39. #ifdef    qSelectionByCharacter
  40.         (*theTextView)->fSelectionStart = 0;
  41.         (*theTextView)->fSelectionEnd = 0;
  42. #else
  43.         (*theTextView)->fSelectionStart = -1;
  44. #endif
  45.         (*theTextView)->fTopLine = 0;
  46.         (*theTextView)->fLineCount = 0;
  47.         (*theTextView)->fTextLineInfoArrayHandle = (TTextLineInfoHandle) NewHandle(0);
  48.         (*theTextView)->fTextHandle = NewHandle(0);
  49.                 
  50.         SetRect(&vScrollbarRect,viewRect->right-kScrollBarThickness,viewRect->top-1,viewRect->right+1,viewRect->bottom-kScrollBarThickness+1);
  51.         SetRect(&hScrollbarRect,viewRect->left-1,viewRect->bottom-kScrollBarThickness,viewRect->right-kScrollBarThickness+1,viewRect->bottom+1);
  52.         
  53.         (*theTextView)->fVerticalScroll = NewControl(theWindow,&vScrollbarRect,"\p",true,0,0,0,scrollBarProc,(unsigned long) theTextView);
  54.         (*theTextView)->fHorizontalScroll = NewControl(theWindow,&hScrollbarRect,"\p",true,0,0,0,scrollBarProc,(unsigned long) theTextView);
  55.  
  56.         SetRect(&(*theTextView)->fTextSizeRect,0,0,0,0);
  57.         }
  58.         
  59.     return(theTextView);
  60.     }
  61.  
  62.  
  63. void    DisposeTextView(TTextViewHandle theTextView)
  64.     {
  65.     DisposeControl((*theTextView)->fVerticalScroll);
  66.     DisposeControl((*theTextView)->fHorizontalScroll);
  67.     DisposeHandle((Handle) (*theTextView)->fTextLineInfoArrayHandle);
  68.     DisposeHandle((*theTextView)->fTextHandle);
  69.     DisposeHandle((Handle) theTextView);    
  70.     }
  71.  
  72.  
  73. void    UpdateTextView(TTextViewHandle theTextView,RgnHandle updateRgn)
  74.     {
  75.     char                textViewHState,lineInfoHState,textHState;
  76.     short                lineIndex;
  77.     char                *textStart,*textEnd,*selStart,*selEnd;
  78.     short                textLength;
  79.     TTextLineInfoPtr    theTextLineInfoArray;
  80.     TTextLineInfoPtr    theTextLine;
  81.     FontInfo            theFontInfo;
  82.     short                lineHeight,verticalPos;
  83.     Rect                textRect,lineRect,updateRect,selectRect;
  84.     Boolean                selectionExists;
  85.     short                horizontalScrollAdjustment;
  86.     RgnHandle            oldClip = NewRgn();
  87.     RgnHandle            textRgn = NewRgn();
  88.     RgnHandle            newClip = NewRgn();
  89.  
  90.     GetClip(oldClip);
  91.  
  92.     horizontalScrollAdjustment = -kHScrollAmount * GetCtlValue((*theTextView)->fHorizontalScroll);
  93.  
  94.     updateRect = (*updateRgn)->rgnBBox;                //    get bounding rectangle for update region
  95.     
  96.     textRect = (*theTextView)->fViewRect;            //    clip to prevent drawing over scrollbars & grow area
  97.     textRect.right -= kScrollBarThickness;
  98.     textRect.bottom -= kScrollBarThickness;
  99.         
  100.     RectRgn(textRgn,&textRect);
  101.     SectRgn(textRgn,updateRgn,newClip);
  102.     SetClip(newClip);
  103.     
  104.     EraseRect(&updateRect);
  105.     
  106.     GetFontInfo(&theFontInfo);
  107.     lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
  108.     verticalPos = theFontInfo.ascent;
  109.     SetRect(&lineRect,0,0,textRect.right,lineHeight);
  110.     
  111.     //    Lock everything down, because we can move memory from here on out
  112.     
  113.     textViewHState    = HGetState((Handle) theTextView);
  114.     lineInfoHState    = HGetState((Handle) (*theTextView)->fTextLineInfoArrayHandle);
  115.     textHState        = HGetState((Handle) (*theTextView)->fTextHandle);
  116.     HLock((Handle) theTextView);
  117.     HLock((Handle) (*theTextView)->fTextLineInfoArrayHandle);
  118.     HLock((Handle) (*theTextView)->fTextHandle);
  119.     
  120.     theTextLineInfoArray = *((*theTextView)->fTextLineInfoArrayHandle);
  121.     theTextLine = &theTextLineInfoArray[(*theTextView)->fTopLine];
  122.     
  123.     selStart = *((*theTextView)->fTextHandle) + (*theTextView)->fSelectionStart;
  124.     selEnd = *((*theTextView)->fTextHandle) + (*theTextView)->fSelectionEnd;
  125.     
  126. #ifdef    qSelectionByCharacter
  127.     selectionExists = selStart != selEnd;
  128. #endif
  129.  
  130.     for (lineIndex=(*theTextView)->fTopLine;lineIndex < (*theTextView)->fLineCount;lineIndex++)
  131.         {                
  132.         textStart = *((*theTextView)->fTextHandle) + theTextLine->fOffsetFromTextStart;
  133.         textLength = theTextLine->fLineLength;
  134.         textEnd = textStart + textLength -1;
  135.         
  136.         if (lineRect.top > updateRect.bottom)            //    if we’re off the bottom of the update rectangle, stop drawing
  137.             break;
  138.         
  139.         if (!RectInRgn(&lineRect,updateRgn))            //    if we aren’t in the update region, skip drawing
  140.             {
  141.             theTextLine++;                                //    next iteration
  142.             OffsetRect(&lineRect,0,lineHeight);
  143.             verticalPos += lineHeight;
  144.  
  145.             continue;
  146.             }
  147.         
  148.         TextFace(theTextLine->fTextStyle);
  149.         MoveTo(kTextViewMargin + horizontalScrollAdjustment,verticalPos);
  150.         DrawText(textStart,0,textLength);
  151.  
  152.         //    Draw selection here if required
  153.  
  154. #ifdef    qSelectionByCharacter
  155. ////////////////////////////////////////////////////////////////////
  156. //
  157. //    Useful code for when character by character selection works
  158. //
  159.         if (selectionExists)
  160.             {
  161.             if ((selStart <= textEnd) && (selEnd >= textStart))        //    if (text is within the selection)
  162.                 {
  163.                 selectRect = lineRect;                                //    first assume text is entirely inside selection
  164.     
  165.                 if (selStart > textStart)    //    start of selection after beginning of line
  166.                     {
  167.                     selectRect.left = kTextViewMargin + horizontalScrollAdjustment + Char2Pixel(textStart,textLength,0,selStart-textStart,1);
  168.                     }
  169.                     
  170.                 if (selEnd < textEnd)        //    end of selection is not at or beyond end of line
  171.                     {
  172.                     selectRect.right = kTextViewMargin + horizontalScrollAdjustment + Char2Pixel(textStart,textLength,0,textEnd-selEnd,1);
  173.                     }
  174.                 
  175.                 SetHiliteMode();
  176.                 InvertRect(&selectRect);
  177.                 }
  178.             }
  179. #else
  180. ////////////////////////////////////////////////////////////////////
  181. //
  182. //    Chezzy code for doing line-by-line selections
  183. //
  184.         if ((*theTextView)->fSelectionStart == lineIndex)
  185.             {
  186.             SetHiliteMode();
  187.             InvertRect(&lineRect);
  188.             }
  189. #endif
  190.             
  191.         theTextLine++;                                // next iteration
  192.         OffsetRect(&lineRect,0,lineHeight);
  193.         verticalPos += lineHeight;
  194.         }
  195.  
  196.     HSetState((Handle) theTextView,textViewHState);
  197.     HSetState((Handle) (*theTextView)->fTextLineInfoArrayHandle,lineInfoHState);
  198.     HSetState((Handle) (*theTextView)->fTextHandle,textHState);
  199.  
  200.     SetClip(oldClip);
  201.     DisposeRgn(newClip);
  202.     DisposeRgn(textRgn);
  203.     DisposeRgn(oldClip);
  204.     }
  205.     
  206.  
  207.  
  208. void    PrintHeader(Rect *pageRectangle,StringPtr documentName,short pageNum,short baseLine)
  209.     {
  210.     Str255                pageNumString;
  211.     Str255                dateStr,timeStr;
  212.     unsigned long        ticks;
  213.  
  214.     TextFace(kPrintHeaderStyle);
  215.  
  216.     //    Draw left-justified date and time
  217.     
  218.     GetDateTime(&ticks);
  219.     IUDateString(ticks,shortDate,dateStr);
  220.     IUTimeString(ticks,false,timeStr);
  221.     MoveTo(0,baseLine);
  222.     DrawString(dateStr);
  223.     DrawString("\p ");
  224.     DrawString(timeStr);
  225.     
  226.     //    Draw right-justified “Page <number>”
  227.     
  228.     NumToString((long) pageNum,pageNumString);
  229.     MoveTo(pageRectangle->right-StringWidth(pageNumString)-StringWidth("\pPage ")-4,baseLine);
  230.     DrawString("\pPage ");
  231.     DrawString(pageNumString);
  232.     
  233.     //    Draw Centered document title
  234.     
  235.     MoveTo((pageRectangle->right + pageRectangle->left - StringWidth(documentName))/2,baseLine);
  236.     DrawString(documentName);
  237.     }
  238.     
  239.  
  240. void    PrintPages(short fontNum,short fontSize,TPPrPort thePrPort,Rect *pageRectangle,StringPtr documentName,TTextViewHandle theTextView)
  241.     {
  242.     char                textViewHState,lineInfoHState,textHState;
  243.     char                *textStart,*textEnd;
  244.     short                textLength;
  245.     TTextLineInfoPtr    theTextLineInfoArray;
  246.     TTextLineInfoPtr    theTextLine;
  247.     FontInfo            theFontInfo;
  248.     short                lineHeight,verticalPos;
  249.     short                linesPerPage,linesToPrint;
  250.     short                lineIndex;
  251.     short                pageNum;
  252.     
  253.     TextFont(fontNum);
  254.     TextSize(fontSize);
  255.     
  256.     GetFontInfo(&theFontInfo);
  257.     lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
  258.     linesPerPage = (pageRectangle->bottom - pageRectangle->top - 2*lineHeight)/lineHeight;
  259.  
  260.     //    Lock everything down, because we can move memory from here on out
  261.     
  262.     textViewHState    = HGetState((Handle) theTextView);
  263.     lineInfoHState    = HGetState((Handle) (*theTextView)->fTextLineInfoArrayHandle);
  264.     textHState        = HGetState((Handle) (*theTextView)->fTextHandle);
  265.  
  266.     HLock((Handle) theTextView);
  267.     HLock((Handle) (*theTextView)->fTextLineInfoArrayHandle);
  268.     HLock((Handle) (*theTextView)->fTextHandle);
  269.     
  270.     theTextLineInfoArray = *((*theTextView)->fTextLineInfoArrayHandle);
  271.  
  272.     theTextLine = &theTextLineInfoArray[0];
  273.     pageNum = 0;
  274.     lineIndex = 0;
  275.     linesToPrint = (*theTextView)->fLineCount;
  276.  
  277.     while (linesToPrint--)
  278.         {
  279.         if (lineIndex == 0)
  280.             {
  281.             if (pageNum != 0)                        //    close previous page if we’re at a page break
  282.                 PrClosePage(thePrPort);
  283.                 
  284.             PrOpenPage(thePrPort,(TPRect) nil);        //    open a new page
  285.             pageNum++;
  286.             
  287.             TextFont(fontNum);                        //    reset the font
  288.             TextSize(fontSize);
  289.             
  290.             verticalPos = pageRectangle->top + theFontInfo.ascent;
  291.             PrintHeader(pageRectangle,documentName,pageNum,verticalPos);
  292.             verticalPos += 2*lineHeight;
  293.             }
  294.  
  295.         textStart = *((*theTextView)->fTextHandle) + theTextLine->fOffsetFromTextStart;
  296.         textLength = theTextLine->fLineLength;
  297.         textEnd = textStart + textLength -1;
  298.                 
  299.         TextFace(theTextLine->fTextStyle);
  300.         MoveTo(kTextViewMargin,verticalPos);
  301.         DrawText(textStart,0,textLength);
  302.             
  303.         theTextLine++;                                // next iteration
  304.         verticalPos += lineHeight;
  305.         lineIndex = (lineIndex + 1) % linesPerPage;
  306.         }
  307.  
  308.     if (pageNum != 0)
  309.         PrClosePage(thePrPort);
  310.     
  311.     HSetState((Handle) theTextView,textViewHState);
  312.     HSetState((Handle) (*theTextView)->fTextLineInfoArrayHandle,lineInfoHState);
  313.     HSetState((Handle) (*theTextView)->fTextHandle,textHState);
  314.     }
  315.  
  316.  
  317.  
  318.     
  319. void    PrintTextView(THPrint printRecord,StringPtr documentName,TTextViewHandle theTextView)
  320.     {
  321.     TPPrPort    aPrPort;
  322.     short        fontNum,fontSize;
  323.     
  324.     fontNum = qd.thePort->txFont;
  325.     fontSize = qd.thePort->txSize;
  326.     
  327.     aPrPort= PrOpenDoc(printRecord,(TPPrPort) nil,(Ptr) nil);
  328.     if (PrError() == noErr)
  329.         PrintPages(fontNum,fontSize,aPrPort,&(*printRecord)->prInfo.rPage,documentName,theTextView);
  330.     PrCloseDoc(aPrPort);
  331.     }
  332.  
  333.  
  334. void    ActivateTextView(TTextViewHandle theTextView,Boolean activating)
  335.     {
  336.     (*theTextView)->fActive = activating;
  337.     
  338.     if (activating)
  339.         {
  340.         HiliteControl((*theTextView)->fVerticalScroll,0);
  341.         HiliteControl((*theTextView)->fHorizontalScroll,0);
  342.         }
  343.     else
  344.         {
  345.         HiliteControl((*theTextView)->fVerticalScroll,254);
  346.         HiliteControl((*theTextView)->fHorizontalScroll,254);
  347.         }
  348.     }
  349.  
  350.  
  351. Boolean    ClickTextView(TTextViewHandle theTextView,Point where,long *lineHit,Boolean isDoubleClick)
  352.     {
  353.     GrafPtr            oldPort;
  354.     ControlHandle    theControl;
  355.     short            partCode;
  356.     short            oldValue,newValue;
  357.     Rect            textRect;
  358.     FontInfo        theFontInfo;
  359.     short            lineHeight;
  360.  
  361.     GetPort(&oldPort);
  362.     SetPort((*theTextView)->fWindow);
  363.     GetFontInfo(&theFontInfo);
  364.     lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
  365.     SetPort(oldPort);
  366.     
  367.     textRect = (*theTextView)->fViewRect;
  368.     textRect.right -= 15;
  369.     textRect.bottom -= 15;
  370.     
  371.     if (PtInRect(where,&textRect))
  372.         {
  373.         *lineHit = (where.v - textRect.top) / lineHeight + (*theTextView)->fTopLine;
  374.         if (*lineHit < (*theTextView)->fLineCount)
  375.             {
  376.             SelectLine(theTextView,*lineHit);
  377.             return(isDoubleClick);
  378.             }
  379.         else
  380.             return(false);
  381.         }
  382.     else if (PtInRect(where,&(*theTextView)->fViewRect))
  383.         {
  384.         partCode = FindControl(where,(*theTextView)->fWindow,&theControl);
  385.         if (partCode != 0)
  386.             {
  387.             if (partCode == inThumb)
  388.                 {
  389.                 oldValue = GetCtlValue(theControl);
  390.                 TrackControl(theControl,where,(ControlActionUPP) nil);
  391.                 newValue = GetCtlValue(theControl);
  392.                 if (newValue != oldValue)
  393.                     {
  394.                     if (theControl == (*theTextView)->fVerticalScroll)
  395.                         (*theTextView)->fTopLine = newValue;
  396.  
  397.                     InvalRect(&(*theTextView)->fViewRect);
  398.                     }
  399.                 }
  400.             else
  401.                 TrackControl(theControl,where,gTextViewActionUPP);
  402.             }
  403.         }
  404.     return(false);
  405.     }
  406.  
  407.  
  408. void    SelectLine(TTextViewHandle theTextView,long lineHit)
  409.     {
  410.     GrafPtr            oldPort;
  411.     TTextLineInfo    ;
  412.     FontInfo        theFontInfo;
  413.     short            lineHeight;
  414.     Rect            newRect,oldRect;
  415.  
  416.     GetPort(&oldPort);
  417.     SetPort((*theTextView)->fWindow);
  418.     GetFontInfo(&theFontInfo);
  419.     lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
  420.     
  421.     SetRect(&newRect,0,0,(*theTextView)->fViewRect.right-15,lineHeight);
  422.     oldRect = newRect;
  423.     OffsetRect(&oldRect,0,((*theTextView)->fSelectionStart-(*theTextView)->fTopLine)*lineHeight);
  424.     OffsetRect(&newRect,0,(lineHit-(*theTextView)->fTopLine)*lineHeight);
  425.  
  426.     SetHiliteMode();        //    get rid of old selection
  427.     InvertRect(&oldRect);
  428.     
  429.     SetHiliteMode();        //    select new line
  430.     InvertRect(&newRect);
  431.  
  432.     (*theTextView)->fSelectionStart = lineHit;
  433.  
  434.     SetPort(oldPort);
  435.     }
  436.  
  437.  
  438. unsigned long    GetTextLineRefCon(TTextViewHandle theTextView,long theLine)
  439.     {
  440.     TTextLineInfo    theTextLine;
  441.     TTextLineInfo    *theTextLineInfoArray;
  442.     
  443.     theTextLineInfoArray = *((*theTextView)->fTextLineInfoArrayHandle);
  444.     theTextLine = theTextLineInfoArray[theLine];
  445.     
  446.     return(theTextLine.fRefCon);
  447.     }
  448.  
  449.  
  450. pascal void    TextViewActionProc(ControlHandle theControl,short partCode)
  451.     {
  452.     TTextViewHandle    theTextView;
  453.     long            topLine,lastTopLine;
  454.     short            lineHeight;
  455.     Rect            textRect;
  456.     RgnHandle        updateRgn = NewRgn();
  457.     FontInfo        theFontInfo;
  458.     short            pageDistanceInPixels;
  459.     short            pageDistanceInWholeLines;
  460.     short            scrollDistance;
  461.     short            hScroll,hScrollMax;
  462.  
  463.     GetFontInfo(&theFontInfo);
  464.     lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
  465.  
  466.     //    a handle to the TTextViewHandle is stored in the refCon    
  467.     
  468.     theTextView = (TTextViewHandle) GetCRefCon(theControl);
  469.     
  470.     topLine = (*theTextView)->fTopLine;
  471.     lastTopLine = GetCtlMax(theControl);
  472.     
  473.     textRect = (*theTextView)->fViewRect;
  474.     textRect.right -= kScrollBarThickness;
  475.     textRect.bottom -= kScrollBarThickness;
  476.     
  477.     pageDistanceInWholeLines = (textRect.bottom - textRect.top) / lineHeight;
  478.     pageDistanceInPixels = (pageDistanceInWholeLines * lineHeight);
  479.     scrollDistance = 0;
  480.  
  481.  
  482.     if (theControl == (*theTextView)->fVerticalScroll)
  483.         {
  484.         switch (partCode)
  485.             {
  486.             case    inUpButton:
  487.                 topLine--;
  488.                 if (topLine >= 0)
  489.                     scrollDistance = lineHeight;
  490.                 break;
  491.                 
  492.             case    inDownButton:
  493.                 topLine++;
  494.                 if (topLine <= lastTopLine)
  495.                     scrollDistance = -lineHeight;
  496.                 break;
  497.                 
  498.             case    inPageUp:
  499.                 topLine -= pageDistanceInWholeLines;
  500.                 scrollDistance = pageDistanceInPixels;
  501.                 
  502.                 if (topLine < 0)
  503.                     {
  504.                     scrollDistance += (topLine * lineHeight);    // subtract off error in scrolldistance
  505.                     topLine = 0;
  506.                     }
  507.                 break;
  508.                 
  509.             case    inPageDown:
  510.                 topLine += pageDistanceInWholeLines;
  511.                 scrollDistance = -pageDistanceInPixels;
  512.                 
  513.                 if (topLine > lastTopLine)
  514.                     {
  515.                     scrollDistance += ((lastTopLine-topLine) * lineHeight);    // subtract off error in scrolldistance
  516.                     topLine = lastTopLine;
  517.                     }
  518.                 break;
  519.             }
  520.                         
  521.         if (scrollDistance != 0)
  522.             {
  523.             (*theTextView)->fTopLine = topLine;
  524.             SetCtlValue(theControl,topLine);
  525.             ScrollRect(&textRect,0,scrollDistance,updateRgn);
  526.             UpdateTextView(theTextView,updateRgn);
  527.             }
  528.         }
  529.     else if (theControl == (*theTextView)->fHorizontalScroll)
  530.         {
  531.         hScroll = GetCtlValue(theControl);
  532.         hScrollMax = GetCtlMax(theControl);
  533.         switch (partCode)
  534.             {
  535.             case    inUpButton:
  536.                 if (hScroll > 0)
  537.                     {
  538.                     hScroll--;
  539.                     scrollDistance = -1;
  540.                     }
  541.                 break;
  542.  
  543.             case    inDownButton:
  544.                 if (hScroll < hScrollMax)
  545.                     {
  546.                     hScroll++;
  547.                     scrollDistance = 1;
  548.                     }
  549.                 break;
  550.  
  551.             case    inPageUp:
  552.                 hScroll -= 5;
  553.                 scrollDistance = -5;
  554.                 if (hScroll < 0)
  555.                     {
  556.                     scrollDistance += -hScroll;        //    add undershoot
  557.                     hScroll = 0;
  558.                     }
  559.                 break;
  560.  
  561.             case    inPageDown:
  562.                 hScroll += 5;
  563.                 scrollDistance = 5;
  564.                 if (hScroll > hScrollMax)
  565.                     {
  566.                     scrollDistance -= (hScroll-hScrollMax);    //    subtract overshoot
  567.                     hScroll = hScrollMax;
  568.                     }
  569.                 break;
  570.         
  571.             default:
  572.                 break;
  573.             }
  574.             
  575.         //    Update hScroll & update the report window
  576.         
  577.         SetCtlValue(theControl,hScroll);
  578.         ScrollRect(&textRect,-kHScrollAmount*scrollDistance,0,updateRgn);        
  579.         UpdateTextView(theTextView,updateRgn);
  580.         }
  581.  
  582.     ResizeTextView(theTextView,&(*theTextView)->fViewRect);
  583.     DisposeRgn(updateRgn);
  584.     }
  585.  
  586.  
  587. void    ScrollTextView(TTextViewHandle theTextView,unsigned long newTopLine)
  588.     {
  589.     GrafPtr    oldPort;
  590.     Rect    textRect;
  591.     
  592.     if (newTopLine > (*theTextView)->fLineCount-1)
  593.         newTopLine = (*theTextView)->fLineCount;
  594.     
  595.     textRect = (*theTextView)->fViewRect;
  596.     textRect.right -= kScrollBarThickness;
  597.     
  598.     GetPort(&oldPort);
  599.     SetPort((*theTextView)->fWindow);
  600.     SetCtlValue((*theTextView)->fVerticalScroll,newTopLine);
  601.     InvalRect(&textRect);
  602.     SetPort(oldPort);
  603.     }
  604.  
  605.  
  606. void    SetTextViewSelection(TTextViewHandle theTextView,unsigned long selStart,unsigned long selEnd)
  607.     {
  608.     unsigned long    temp;
  609.  
  610.     if (selStart > selEnd)
  611.         {
  612.         temp = selStart;
  613.         selStart = selEnd;
  614.         selEnd = temp;
  615.         }
  616.         
  617.     (*theTextView)->fSelectionStart = selStart;    
  618.     (*theTextView)->fSelectionEnd = selEnd;    
  619.     }
  620.  
  621.  
  622. void    GetTextViewSelection(TTextViewHandle theTextView,unsigned long *selStart,unsigned long *selEnd)
  623.     {
  624.     *selStart = (*theTextView)->fSelectionStart;    
  625.     *selEnd = (*theTextView)->fSelectionEnd;    
  626.     }
  627.  
  628.  
  629. void    ResizeTextView(TTextViewHandle theTextView,Rect *newSize)
  630.     {
  631.     GrafPtr        oldPort;
  632.     Rect        viewRect,vScrollbarRect,hScrollbarRect;
  633.     short        lineHeight,newHeightInLines,newVScrollMax;
  634.     short        maxTextWidth,windowWidth,oldHScroll,newHScrollMax;
  635.     FontInfo    theFontInfo;
  636.     
  637.     GetPort(&oldPort);
  638.     SetPort((*theTextView)->fWindow);
  639.     
  640.     GetFontInfo(&theFontInfo);
  641.     lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
  642.     
  643.     viewRect = (*theTextView)->fViewRect;
  644.  
  645.     if (!EqualRect(&viewRect,newSize))
  646.         {
  647.         //    If we really changed size, then move the scrollbars around!
  648.         
  649.         //    Invalidate vertical scrollbar rectangle and horizontal scrollbar rectangle and grow box
  650.         
  651.         SetRect(&vScrollbarRect,viewRect.right-kScrollBarThickness,viewRect.top-1,viewRect.right+1,viewRect.bottom-kScrollBarThickness+1);
  652.         SetRect(&hScrollbarRect,viewRect.left-1,viewRect.bottom-kScrollBarThickness,viewRect.right-1,viewRect.bottom+1);
  653.         InvalRect(&vScrollbarRect);
  654.         InvalRect(&hScrollbarRect);
  655.     
  656.         //    move the scrollbars to new locations and redraw them
  657.  
  658.         HideControl((*theTextView)->fVerticalScroll);
  659.         HideControl((*theTextView)->fHorizontalScroll);
  660.         MoveControl((*theTextView)->fVerticalScroll,newSize->right-kScrollBarThickness,newSize->top-1);
  661.         SizeControl((*theTextView)->fVerticalScroll,16,newSize->bottom-newSize->top-kScrollBarThickness+2);
  662.         MoveControl((*theTextView)->fHorizontalScroll,newSize->left-1,newSize->bottom-kScrollBarThickness);
  663.         SizeControl((*theTextView)->fHorizontalScroll,newSize->right-newSize->left-kScrollBarThickness+2,16);
  664.         DrawControls((*theTextView)->fWindow);
  665.         ShowControl((*theTextView)->fVerticalScroll);
  666.         ShowControl((*theTextView)->fHorizontalScroll);
  667.  
  668.         //    Validate the new scrollbar rectangles (so we don’t double draw)
  669.         
  670.         SetRect(&vScrollbarRect,newSize->right-kScrollBarThickness,newSize->top-1,newSize->right+1,newSize->bottom-kScrollBarThickness+1);
  671.         SetRect(&hScrollbarRect,newSize->left-1,newSize->bottom-kScrollBarThickness,newSize->right-kScrollBarThickness+1,newSize->bottom+1);
  672.         ValidRect(&vScrollbarRect);
  673.         ValidRect(&hScrollbarRect);
  674.  
  675.         /*    Invalidate the grow box    too    */
  676.         
  677.         viewRect = *newSize;
  678.         viewRect.left = viewRect.right-15;
  679.         viewRect.top = viewRect.bottom - 15;
  680.         InvalRect(&viewRect);
  681.     
  682.         //    Update the TextView Record
  683.     
  684.         (*theTextView)->fViewRect = *newSize;
  685.         }
  686.  
  687.     //    ---> Regardless of whether or not this is a new size, recalc the scrollbar max values
  688.  
  689.     //    Update maximum value for vertical scroll
  690.  
  691.     newHeightInLines = (newSize->bottom-newSize->top-kScrollBarThickness-kTextViewMargin) / lineHeight;
  692.     newVScrollMax = (*theTextView)->fLineCount - newHeightInLines;
  693.     if (newVScrollMax < 0)
  694.         newVScrollMax = (*theTextView)->fTopLine;
  695.     SetCtlMax((*theTextView)->fVerticalScroll,newVScrollMax);
  696.  
  697.  
  698.     //    Update maximum value for horizontal scroll
  699.  
  700.     maxTextWidth = (*theTextView)->fTextSizeRect.right - (*theTextView)->fTextSizeRect.left;
  701.     windowWidth = newSize->right-newSize->left-kTextViewMargin-kScrollBarThickness-kHScrollAmount;
  702.     
  703.     oldHScroll = GetCtlValue((*theTextView)->fHorizontalScroll);
  704.     
  705.     newHScrollMax = (maxTextWidth - windowWidth) / kHScrollAmount;
  706.     if (newHScrollMax < oldHScroll)
  707.         newHScrollMax = oldHScroll;
  708.     SetCtlMax((*theTextView)->fHorizontalScroll,newHScrollMax);    
  709.     SetPort(oldPort);
  710.     }
  711.  
  712.  
  713. void    AddStringToTextView(TTextViewHandle theTextView,Str255 theTextToAdd,Style theTextStyle,long refCon)
  714.     {
  715.     GrafPtr                oldPort;
  716.     Size                textHandleSize,lineInfoArrayHandleSize;
  717.     TTextLineInfoPtr    theTextLine;
  718.     long                stringLength;
  719.     char                *eolPtr;
  720.     FontInfo            theFontInfo;
  721.     short                lineHeight,lineWidth;
  722.  
  723.     GetPort(&oldPort);
  724.     SetPort((*theTextView)->fWindow);
  725.     
  726.     GetFontInfo(&theFontInfo);
  727.     lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
  728.  
  729.     stringLength = theTextToAdd[0];
  730.     
  731.     textHandleSize = GetHandleSize((*theTextView)->fTextHandle);
  732.     SetHandleSize((*theTextView)->fTextHandle,textHandleSize + stringLength+1);
  733.  
  734.     if (MemError() != noErr)            //    unable to bump text handle up, so punt
  735.         return;
  736.     
  737.     lineInfoArrayHandleSize = GetHandleSize((Handle) (*theTextView)->fTextLineInfoArrayHandle);
  738.     SetHandleSize((Handle) (*theTextView)->fTextLineInfoArrayHandle, lineInfoArrayHandleSize + sizeof(TTextLineInfo));
  739.     
  740.     if (MemError() != noErr)            //    unable to alloc an additional lineinfo record, punt!
  741.         {
  742.         SetHandleSize((*theTextView)->fTextHandle,textHandleSize);
  743.         return;
  744.         }
  745.     
  746.     theTextLine = &(*(*theTextView)->fTextLineInfoArrayHandle)[(*theTextView)->fLineCount];
  747.     theTextLine->fOffsetFromTextStart = textHandleSize;
  748.     theTextLine->fLineLength = stringLength;
  749.     theTextLine->fRefCon = refCon;
  750.     theTextLine->fTextStyle = theTextStyle;
  751.  
  752.     (*theTextView)->fLineCount++;        // bump line count
  753.  
  754.     TextFace(theTextStyle);
  755.     lineWidth = StringWidth(theTextToAdd);
  756.     
  757.     if (lineWidth > (*theTextView)->fTextSizeRect.right-(*theTextView)->fTextSizeRect.left)
  758.         (*theTextView)->fTextSizeRect.right = (*theTextView)->fTextSizeRect.left + lineWidth;
  759.     
  760.     (*theTextView)->fTextSizeRect.bottom += lineHeight;        //    bump textSizeRectangle
  761.     
  762.     // copy string to text buffer
  763.     
  764.     BlockMove(&theTextToAdd[1],*((*theTextView)->fTextHandle)+textHandleSize,stringLength);
  765.  
  766.     eolPtr = *((*theTextView)->fTextHandle)+textHandleSize+stringLength;
  767.     *eolPtr = 13;
  768.     
  769.     SetPort(oldPort);
  770.     }
  771.